home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / msdos / nec765.c < prev    next >
C/C++ Source or Header  |  1999-09-02  |  32KB  |  1,093 lines

  1. /*****************************************************************************
  2.  *
  3.  *    nec765.c
  4.  *
  5.  *    allow direct access to a PCs NEC 765 floppy disc controller
  6.  *
  7.  *    !!!! this is ALPHA - be careful !!!!
  8.  *
  9.  *****************************************************************************/
  10.  
  11. #include <go32.h>
  12. #include <pc.h>
  13. #include <dpmi.h>
  14. #include <time.h>
  15. #include "driver.h"
  16. #include "mess/machine/wd179x.h"
  17.  
  18. #define RE_INTERLEAVE    0
  19. #define VERBOSE         1
  20. /* since most PC floppy disc controllers don't really support FM, */
  21. /* set this to 0x40 to always format/read/write in MFM mode */
  22. #define MFM_OVERRIDE    0x40
  23.  
  24. #if VERBOSE
  25. #define LOG(msg) if (log) fprintf msg
  26. #else
  27. #define LOG(msg)
  28. #endif
  29.  
  30. typedef struct
  31. {
  32.     unsigned drive_0:1;             /* drive 0 in seek mode / busy */
  33.     unsigned drive_1:1;             /* drive 1 in seek mode / busy */
  34.     unsigned drive_2:1;             /* drive 2 in seek mode / busy */
  35.     unsigned drive_3:1;             /* drive 3 in seek mode / busy */
  36.     unsigned io_active:1;            /* read or write command in progress */
  37.     unsigned non_dma_mode:1;        /* fdc is in non DMA mode if set */
  38.     unsigned read_from_fdc:1;        /* request for master (1 fdc->cpu, 0 cpu->fdc) */
  39.     unsigned ready:1;                /* data reg ready for i/o */
  40. }   STM;
  41.  
  42. typedef struct
  43. {
  44.     unsigned unit_select:2;         /* unit select */
  45.     unsigned head:1;                /* head */
  46.     unsigned not_ready:1;            /* not ready */
  47.     unsigned equip_check:1;         /* equipment check (drive fault) */
  48.     unsigned seek_end:1;            /* seek end */
  49.     unsigned int_code:2;            /* interrupt code (0: ok, 1:abort, 2:ill cmd, 3:ready chg) */
  50. }   ST0;
  51.  
  52. typedef struct
  53. {
  54.     unsigned missing_AM:1;            /* missing address mark */
  55.     unsigned not_writeable:1;        /* not writeable */
  56.     unsigned no_data:1;             /* no data */
  57.     unsigned x3:1;                    /* always 0 */
  58.     unsigned overrun:1;             /* overrun */
  59.     unsigned data_error:1;            /* data error */
  60.     unsigned x6:1;                    /* always 0 */
  61.     unsigned end_of_cylinder:2;     /* end of cylinder */
  62. }   ST1;
  63.  
  64. typedef struct
  65. {
  66.     unsigned missing_DAM:1;         /* missing (deleted) data address mark */
  67.     unsigned bad_cylinder:1;        /* bad cylinder (cylinder == 255) */
  68.     unsigned scan_not_satisfied:1;    /* scan not satisfied */
  69.     unsigned scan_equal_hit:1;        /* scan equal hit */
  70.     unsigned wrong_cylinder:1;        /* wrong cylinder (mismatch) */
  71.     unsigned data_error:1;            /* data error */
  72.     unsigned control_mark:1;        /* control mark (deleted data address mark) */
  73.     unsigned x7:1;                    /* always 0 */
  74. }   ST2;
  75.  
  76. typedef struct
  77. {
  78.     unsigned unit_select:2;         /* unit select */
  79.     unsigned head:1;                /* head */
  80.     unsigned two_side:1;            /* two side */
  81.     unsigned track_0:1;             /* track 0 (not reliable!?) */
  82.     unsigned ready:1;                /* ready */
  83.     unsigned write_protect:1;        /* write protect */
  84.     unsigned fault:1;                /* fault */
  85. }   ST3;
  86.  
  87.  
  88. typedef struct
  89. {
  90.     ST0 st0;            /* status 0 */
  91.     ST1 st1;            /* status 1 */
  92.     ST2 st2;            /* status 2 */
  93.     UINT8 c;             /* cylinder */
  94.     UINT8 h;             /* head */
  95.     UINT8 s;             /* sector */
  96.     UINT8 n;             /* sector length */
  97.     ST3 st3;            /* status 3 (after sense drive status cmd) */
  98.     UINT8 pcn;
  99. }   STA;
  100.  
  101. typedef struct
  102. {
  103.     UINT8 unit;          /* unit number 0 = A:, 1 = B: */
  104.     UINT8 type;          /* type of drive 0: 360K, 1: 720K, 2: 1.2M, 3: 1.44M */
  105.     UINT8 eot;             /* end of track */
  106.     UINT8 secl;          /* sector length code (0:128, 1:256, 2:512 ... ) */
  107.     UINT8 gap_a;         /* read/write gap A*/
  108.     UINT8 gap_b;         /* format gap B */
  109.     UINT8 dtl;             /* data length (128 if secl == 0) */
  110.     UINT8 filler;         /* format filler UINT8 (E5) */
  111.     UINT8 mfm;             /* 0x00 = FM, 0x40 = MFM */
  112.     UINT8 rcmd;          /* read command (0x26 normal, 0x2C deleted data address mark) */
  113.     UINT8 wcmd;          /* write command (0x05 normal, 0x09 deleted data address mark) */
  114.     UINT8 dstep;         /* double step shift factor (1 for 40 track disk in 80 track drive) */
  115.     STM stm;            /* main status */
  116.     STA sta;            /* status file */
  117. }   NEC;
  118.  
  119. typedef struct {
  120.     UINT8 density;
  121.     UINT8 spt;
  122.     UINT8 secl;
  123.     UINT8 gap_a;
  124.     UINT8 gap_b;
  125. }    GAPS;
  126.  
  127. static GAPS gaps[] = {
  128.     {DEN_FM_LO,    1, 4, 200, 255},
  129.     {DEN_FM_LO,    2, 3, 200, 255},
  130.     {DEN_FM_LO,    4, 2,  70, 135},
  131.     {DEN_FM_LO,    5, 2,  56,  98},
  132.     {DEN_FM_LO,    5, 1, 200, 255},
  133.     {DEN_FM_LO,    6, 1,  70, 135},
  134.     {DEN_FM_LO,    7, 1,  56,  98},
  135.     {DEN_FM_LO,    8, 1,  25,  48},
  136.     {DEN_FM_LO,    9, 1,   7,   9},
  137.     {DEN_FM_LO,   16, 0,  16,  25},
  138.     {DEN_FM_LO,   17, 0,  11,  17},
  139.     {DEN_FM_LO,   18, 0,   7,   9},
  140.  
  141.     {DEN_FM_HI,    2, 4, 200, 255},
  142.     {DEN_FM_HI,    3, 4,  42,  80},
  143.     {DEN_FM_HI,    4, 3, 128, 240},
  144.     {DEN_FM_HI,    5, 3,  70, 135},
  145.     {DEN_FM_HI,    8, 2,  42,  80},
  146.     {DEN_FM_HI,    9, 2,  42,  80},
  147.     {DEN_FM_HI,   10, 2,  10,  12},
  148.     {DEN_FM_HI,   16, 1,  32,  50},
  149.     {DEN_FM_HI,   18, 1,  10,  12},
  150.     {DEN_FM_HI,   26, 0,   7,   9},
  151.  
  152.     {DEN_MFM_LO,   1, 5, 200, 255},
  153.     {DEN_MFM_LO,   2, 4, 200, 255},
  154.     {DEN_MFM_LO,   3, 4,  26,  46},
  155.     {DEN_MFM_LO,   4, 3, 128, 240},
  156.     {DEN_MFM_LO,   5, 3,  21,  31},
  157.     {DEN_MFM_LO,   8, 2,  42,  80},
  158.     {DEN_MFM_LO,   9, 2,  26,  46},
  159.     {DEN_MFM_LO,  10, 2,  10,  12},
  160.     {DEN_MFM_LO,  16, 1,  32,  50},
  161.     {DEN_MFM_LO,  17, 1,  21,  31},
  162.     {DEN_MFM_LO,  18, 1,  10,  12},
  163.     {DEN_MFM_LO,  19, 1,   7,   9},
  164.  
  165.     {DEN_MFM_HI,  2,  5, 200, 255},
  166.     {DEN_MFM_HI,  4,  4, 200, 255},
  167.     {DEN_MFM_HI,  5,  4,  42,  80},
  168.     {DEN_MFM_HI,  8,  3, 128, 240},
  169.     {DEN_MFM_HI,  9,  3,  76, 148},
  170.     {DEN_MFM_HI, 10,  3,  32,  50},
  171.     {DEN_MFM_HI, 11,  3,  10,  12},
  172.     {DEN_MFM_HI, 16,  2, 128, 240},
  173.     {DEN_MFM_HI, 17,  2,  70, 135},
  174.     {DEN_MFM_HI, 18,  2,  42,  80},
  175.     {DEN_MFM_HI, 19,  2,  32,  50},
  176.     {DEN_MFM_HI, 32,  1, 128, 240},
  177.     {DEN_MFM_HI, 33,  1,  42,  80},
  178.     {DEN_MFM_HI, 34,  1,  32,  50},
  179.     {DEN_MFM_HI, 35,  1,  21,  31},
  180.     {DEN_MFM_HI, 36,  1,  10,  12},
  181.     {0,0,0,0,0}
  182. };
  183.  
  184. static FILE *log = NULL;
  185. static NEC nec;
  186. static UINT8 unit_type[4] = {0xff, 0xff, 0xff, 0xff};
  187.  
  188. static __dpmi_paddr old_irq_E;    /* previous interrupt vector 0E */
  189. static __dpmi_paddr new_irq_E;    /* new interrupt vector 0E */
  190. static _go32_dpmi_seginfo nec_dma; /* for allocation of a sector DMA buffer */
  191. static UINT8 irq_flag = 0;         /* set by IRQ 6 (INT 0E) */
  192. static UINT8 initialized = 0;
  193. static void *timer_motors = NULL;
  194.  
  195. /*****************************************************************************
  196.  * convert NEC 765 status to WD179X status 1 (restore, seek, step)
  197.  *****************************************************************************/
  198. static UINT8 FDC_STA1(void)
  199. {
  200.     UINT8 sta = 0;
  201.  
  202. #if 0    /* since the track_0 status seems not to be reliable */
  203.     if (!nec.sta.st3.track_0)       /* track 0 */
  204.         sta |= STA_1_TRACK0;
  205. #else    /* I did it that way */
  206.     if (!nec.sta.pcn == 0)            /* cylinder number 0 */
  207.         sta |= STA_1_TRACK0;
  208. #endif
  209.     if (nec.sta.st3.write_protect)  /* write protect */
  210.         sta |= STA_1_WRITE_PRO;
  211.     if (!nec.sta.st3.ready)         /* not ready */
  212.         sta |= STA_1_NOT_READY;
  213.  
  214.     return sta;
  215. }
  216.  
  217. /*****************************************************************************
  218.  * convert NEC 765 status to WD179X status 2 (read, write, format)
  219.  *****************************************************************************/
  220. static UINT8 FDC_STA2(int read_mode)
  221. {
  222.     UINT8 sta = 0;
  223.  
  224.     if (nec.sta.st1.overrun)        /* overrun ? */
  225.         sta |= STA_2_LOST_DAT;
  226.     if (nec.sta.st1.data_error ||    /* data error (DAM) ? */
  227.         nec.sta.st2.data_error)     /* data error (SEC) ? */
  228.         sta |= STA_2_CRC_ERR;
  229.     if (nec.sta.st1.no_data ||        /* no data ? */
  230.         nec.sta.st1.missing_AM)     /* missing address mark ? */
  231.         sta |= STA_2_REC_N_FND;
  232.     if (nec.sta.st2.control_mark)    /* control mark ? */
  233.         sta |= STA_2_REC_TYPE;
  234.     if (nec.sta.st1.not_writeable)    /* not writeable ? */
  235.         sta |= STA_2_WRITE_PRO;
  236.     if (nec.sta.st0.int_code == 3)    /* interrupt code == ready change ? */
  237.         sta |= STA_2_NOT_READY;
  238.  
  239.     if (read_mode && !(sta & ~STA_2_REC_TYPE))
  240.         sta |= STA_2_DRQ | STA_2_BUSY;
  241.  
  242.     return sta;
  243. }
  244.  
  245. /*****************************************************************************
  246.  * initialize dma controller to read count bytes to ofs
  247.  *****************************************************************************/
  248. static void dma_read(int count)
  249. {
  250.     int ofs = nec_dma.rm_segment * 16 + nec_dma.rm_offset;
  251.  
  252.     LOG((log,"NEC765  dma_read %08X %04X\n", ofs, count));
  253.     outportb(0x0a, 0x04 | 0x02);        /* mask DMA channel 2 */
  254.     outportb(0x0b, 0x46);                /* DMA read command */
  255.     outportb(0x0c, 0);                    /* reset first/last flipflop */
  256.     outportb(0x05, (count - 1) & 0xff); /* transfer size low */
  257.     outportb(0x05, (count - 1) >> 8);    /* transfer size high */
  258.     outportb(0x04, ofs & 0xff);         /* transfer offset low */
  259.     outportb(0x04, (ofs >> 8) & 0xff);    /* transfer offset high */
  260.     outportb(0x81, (ofs >> 16) & 0xff); /* select 64k page */
  261.     outportb(0x0a, 0x02);                /* start DMA channel 2 */
  262. }
  263.  
  264. /*****************************************************************************
  265.  * initialize dma controller to read count bytes to ofs
  266.  *****************************************************************************/
  267. static void dma_write(int count)
  268. {
  269.     int ofs = nec_dma.rm_segment * 16 + nec_dma.rm_offset;
  270.  
  271.     LOG((log,"NEC765  dma_write %08X %04X\n", ofs, count));
  272.     outportb(0x0a, 0x04 | 0x02);        /* mask DMA channel 2 */
  273.     outportb(0x0b, 0x4a);                /* DMA write command */
  274.     outportb(0x0c, 0);                    /* reset first/last flipflop */
  275.     outportb(0x05, (count - 1) & 0xff); /* transfer size low */
  276.     outportb(0x05, (count - 1) >> 8);    /* transfer size high */
  277.     outportb(0x04, ofs & 0xff);         /* transfer offset low */
  278.     outportb(0x04, (ofs >> 8) & 0xff);    /* transfer offset high */
  279.     outportb(0x81, (ofs >> 16) & 0xff); /* select 64k page */
  280.     outportb(0x0a, 0x02);                /* start DMA channel 2 */
  281. }
  282.  
  283. /*****************************************************************************
  284.  * read NECs main status
  285.  *****************************************************************************/
  286. static int main_status(void)
  287. {
  288.     uclock_t timeout;
  289.     uclock_t utime = uclock();
  290.  
  291.     timeout = utime + UCLOCKS_PER_SEC;
  292.     while (utime < timeout)
  293.     {
  294.         *(UINT8 *)&nec.stm = inportb(0x3f4);
  295.         if (nec.stm.ready)
  296.             break;
  297.         utime = uclock();
  298.     }
  299.  
  300.     timeout -= uclock();
  301.  
  302.     if (timeout <= 0)
  303.     {
  304.         LOG((log,"NEC765  STM: %02X RDY%c DIR%c IO%c NDMA%c %c%c%c%c\n",
  305.             *(UINT8 *) &nec.stm,
  306.             (nec.stm.ready) ? '*' : '-',
  307.             (nec.stm.read_from_fdc) ? '-' : '+',
  308.             (nec.stm.io_active) ? '*' : '-',
  309.             (nec.stm.non_dma_mode) ? '*' : '-',
  310.             (nec.stm.drive_0) ? 'A' : '*',
  311.             (nec.stm.drive_1) ? 'B' : '*',
  312.             (nec.stm.drive_2) ? 'C' : '*',
  313.             (nec.stm.drive_3) ? 'D' : '*'));
  314.     }
  315.     return (timeout > 0);
  316. }
  317.  
  318. /*****************************************************************************
  319.  * NECs results phase: read everything into the status registers
  320.  *****************************************************************************/
  321. static void results(int sense_interrupt)
  322. {
  323.  
  324.     if (sense_interrupt)
  325.     {
  326.         if (main_status() && nec.stm.read_from_fdc)
  327.         {
  328.             *(UINT8*)&nec.sta.st3 = inportb(0x3F5);
  329.             LOG((log,"NEC765  ST3: 0x%02X US%d HD%d TS%c T0%c RY%c WP%c FT%c\n",
  330.                 *(UINT8*)&nec.sta.st3,
  331.                 nec.sta.st3.unit_select,
  332.                 nec.sta.st3.head,
  333.                 (nec.sta.st3.two_side) ? '*' : '-',
  334.                 (nec.sta.st3.track_0) ? '*' : '-',
  335.                 (nec.sta.st3.ready) ? '*' : '-',
  336.                 (nec.sta.st3.write_protect) ? '*' : '-',
  337.                 (nec.sta.st3.fault) ? '*' : '-'));
  338.         }
  339.         if (main_status() && nec.stm.read_from_fdc)
  340.         {
  341.             *(UINT8*)&nec.sta.pcn = inportb(0x3F5);
  342.             LOG((log,"NEC765  PCN: %02d\n", nec.sta.pcn));
  343.         }
  344.     }
  345.     else
  346.     {
  347.         if (main_status() && nec.stm.read_from_fdc)
  348.         {
  349.             *(UINT8*)&nec.sta.st0 = inportb(0x3F5);
  350.             LOG((log,"NEC765  ST0: 0x%02X US%d HD%d NR%c EC%c SE%c IC%d\n",
  351.                 *(UINT8*)&nec.sta.st0,
  352.                 nec.sta.st0.unit_select,
  353.                 nec.sta.st0.head,
  354.                 (nec.sta.st0.not_ready) ? '*' : '-',
  355.                 (nec.sta.st0.equip_check) ? '*' : '-',
  356.                 (nec.sta.st0.seek_end) ? '*' : '-',
  357.                 nec.sta.st0.int_code));
  358.         }
  359.         if (main_status() && nec.stm.read_from_fdc)
  360.         {
  361.             *(UINT8*)&nec.sta.st1 = inportb(0x3F5);
  362.             LOG((log,"NEC765  ST1: 0x%02X MA%c NW%c ND%c OR%c DE%c EC%c\n",
  363.                 *(UINT8*)&nec.sta.st1,
  364.                 (nec.sta.st1.missing_AM) ? '*' : '-',
  365.                 (nec.sta.st1.not_writeable) ? '*' : '-',
  366.                 (nec.sta.st1.no_data) ? '*' : '-',
  367.                 (nec.sta.st1.overrun) ? '*' : '-',
  368.                 (nec.sta.st1.data_error) ? '*' : '-',
  369.                 (nec.sta.st1.end_of_cylinder) ? '*' : '-'));
  370.         }
  371.         if (main_status() && nec.stm.read_from_fdc)
  372.         {
  373.             *(UINT8*)&nec.sta.st2 = inportb(0x3F5);
  374.             LOG((log,"NEC765  ST2: 0x%02X MD%c BC%c SN%c SH%c WC%c DD%c CM%c\n",
  375.                 *(UINT8*)&nec.sta.st2,
  376.                 (nec.sta.st2.missing_DAM) ? '*' : '-',
  377.                 (nec.sta.st2.bad_cylinder) ? '*' : '-',
  378.                 (nec.sta.st2.scan_not_satisfied) ? '*' : '-',
  379.                 (nec.sta.st2.scan_equal_hit) ? '*' : '-',
  380.                 (nec.sta.st2.wrong_cylinder) ? '*' : '-',
  381.                 (nec.sta.st2.data_error) ? '*' : '-',
  382.                 (nec.sta.st2.control_mark) ? '*' : '-'));
  383.         }
  384.  
  385.         if (main_status() && nec.stm.read_from_fdc)
  386.         {
  387.             *(UINT8*)&nec.sta.c = inportb(0x3F5);
  388.             LOG((log,"NEC765       C:%02d", nec.sta.c));
  389.         }
  390.         if (main_status() && nec.stm.read_from_fdc)
  391.         {
  392.             *(UINT8*)&nec.sta.h = inportb(0x3F5);
  393.             LOG((log," H:%d", nec.sta.h));
  394.         }
  395.         if (main_status() && nec.stm.read_from_fdc)
  396.         {
  397.             *(UINT8*)&nec.sta.s = inportb(0x3F5);
  398.             LOG((log," S:%02d", nec.sta.s));
  399.         }
  400.         if (main_status() && nec.stm.read_from_fdc)
  401.         {
  402.             *(UINT8*)&nec.sta.n = inportb(0x3F5);
  403.             LOG((log," N:%2d", nec.sta.n));
  404.         }
  405.         LOG((log,"\n"));
  406.     }
  407.  
  408. /* more data? shouldn't happen, but read it away */
  409.     while (main_status() && nec.stm.read_from_fdc)
  410.     {
  411.         UINT8 data = inportb(0x3F5);
  412.  
  413.         LOG((log,"NEC765  read unexpected %02X\n", data));
  414.     }
  415. }
  416.  
  417. /*****************************************************************************
  418.  * out_nec: send a UINT8 to the NEC
  419.  *****************************************************************************/
  420. static int out_nec(UINT8 b)
  421. {
  422.     int result = 1;
  423.  
  424.     if (main_status())
  425.     {
  426.         if (nec.stm.read_from_fdc)
  427.         {
  428.             LOG((log,"NEC765   read_from_fdc!\n"));
  429.             results(0);
  430.         }
  431.         else
  432.         {
  433.             LOG((log,"0x%02X ", b));
  434.             outportb(0x3f5, b);
  435.             result = 0;
  436.         }
  437.     }
  438.     return result;
  439. }
  440.  
  441. /*****************************************************************************
  442.  * seek_exec: wait until seek is executed and sense interrupt status
  443.  *****************************************************************************/
  444. static void seek_exec(UINT8 * track)
  445. {
  446.     uclock_t timeout;
  447.     uclock_t utime = uclock();
  448.  
  449.     timeout = utime + UCLOCKS_PER_SEC * 5;
  450.  
  451.     while (utime < timeout)
  452.     {
  453.         main_status();
  454.         if (irq_flag)
  455.             break;
  456.         utime = uclock();
  457.     }
  458.  
  459.     timeout -= uclock();
  460.  
  461.     if (nec.stm.read_from_fdc)
  462.         results(0);
  463.  
  464.     LOG((log,"NEC765  command "));
  465.     if (out_nec(0x08))      /* sense interrupt status */
  466.         return;
  467.     LOG((log,"\n"));
  468.  
  469.     results(1);
  470.  
  471.     if (track)
  472.         *track = nec.sta.pcn;
  473. }
  474.  
  475. /*****************************************************************************
  476.  * specify drive parameters
  477.  * step rate, head unload timing, head load timing, DMA mode
  478.  *****************************************************************************/
  479. static void specify(void)
  480. {
  481.     uclock_t timeout;
  482.     uclock_t utime = uclock();
  483.  
  484.     LOG((log,"NEC765 specify\n"));
  485.  
  486.     timeout = utime + UCLOCKS_PER_SEC;
  487.     irq_flag = 0;
  488.     outportb(0x3f2, 0x08);      /* reset fdc */
  489.     while (utime < timeout)
  490.     {
  491.         if (irq_flag)
  492.             break;
  493.         utime = uclock();
  494.     }
  495.     osd_fdc_motors(nec.unit);   /* take away reset */
  496.  
  497.     LOG((log,"NEC765  command "));
  498.     if (out_nec(0x03))          /* specify command */
  499.         return;
  500.     if (out_nec(0xdf))            /* steprate, head unload timing */
  501.         return;
  502.     if (out_nec(0x04))            /* head load timing, DMA mode */
  503.         return;
  504.     LOG((log,"\n"));
  505.  
  506. }
  507.  
  508. /*****************************************************************************
  509.  * read_sector:
  510.  * read a sector number 'sector' from track 'track', side 'side' using head
  511.  * number 'head' of the floppy disk. if the first try fails, change the
  512.  * DDAM mode and try again
  513.  *****************************************************************************/
  514. static UINT8 read_sector(UINT8 track, UINT8 side, UINT8 head, UINT8 sector)
  515. {
  516.     int try;
  517.  
  518.     LOG((log,"NEC765 read    unit:%d track:%02d side:%d head:%d sector:%d\n",
  519.         nec.unit, track, side, head, sector));
  520.  
  521.     /* three tries to detect normal / deleted data address mark */
  522.     for (try = 0; try < 3; try++)
  523.     {
  524.         dma_read((nec.secl) ? nec.secl << 8 : nec.dtl);
  525.  
  526.         irq_flag = 0;
  527.  
  528.         LOG((log,"NEC765  command "));
  529.         if (out_nec(nec.mfm | nec.rcmd))        /* read sector */
  530.             return STA_2_NOT_READY;
  531.         if (out_nec((side << 2) + nec.unit))    /* side * 4 + unit */
  532.             return STA_2_NOT_READY;
  533.         if (out_nec(track))                     /* track */
  534.             return STA_2_NOT_READY;
  535.         if (out_nec(head))                        /* head (can be 0 for side 1!) */
  536.             return STA_2_NOT_READY;
  537.         if (out_nec(sector))                    /* sector */
  538.             return STA_2_NOT_READY;
  539.         if (out_nec(nec.secl))                    /* bytes per sector */
  540.             return STA_2_NOT_READY;
  541.         if (out_nec(nec.eot))                    /* end of track */
  542.             return STA_2_NOT_READY;
  543.         if (out_nec(nec.gap_a))                 /* gap A */
  544.             return STA_2_NOT_READY;
  545.         if (out_nec(nec.dtl))                    /* data length */
  546.             return STA_2_NOT_READY;
  547.         LOG((log,"\n"));
  548.  
  549.         for ( ; ; )
  550.         {
  551.             main_status();
  552.             if (irq_flag)
  553.                 break;
  554. //            if (!nec.stm.io_active)
  555. //                break;
  556.         }
  557.  
  558.         results(0);
  559.  
  560.         if (!nec.sta.st2.control_mark)
  561.             break;
  562.  
  563.         /* if control mark is set, toggle DDAM mode and try again */
  564.         nec.rcmd ^= 0x0A;       /* toggle between 0x26 and 0x2C */
  565.     }
  566.  
  567.     nec.sta.st2.control_mark = 0;
  568.     /* set status 2 control_mark if read deleted was successful */
  569.     if (nec.rcmd & 0x08)
  570.     {
  571.         LOG((log,"NEC765 read    *DDAM*\n"));
  572.         nec.sta.st2.control_mark = 1;
  573.         nec.rcmd ^= 0x0A;       /* toggle back */
  574.     }
  575.  
  576.     return FDC_STA2(1);
  577. }
  578.  
  579. /*****************************************************************************
  580.  * write_sector:
  581.  * write sector number 'sector' to track 'track', side 'side' of
  582.  * the floppy disk using head number 'head'. if ddam in non zero,
  583.  * write the sector with deleted data address mark (DDAM)
  584.  *****************************************************************************/
  585. static UINT8 write_sector(UINT8 track, UINT8 side, UINT8 head, UINT8 sector, UINT8 ddam)
  586. {
  587.     int i;
  588.  
  589.     LOG((log,"NEC765 write   unit:%d track:%02d side:%d head:%d sector:%d%s\n",
  590.         nec.unit, track, side, head, sector, (ddam) ? " *DDAM*" : ""));
  591.  
  592.     irq_flag = 0;
  593.  
  594.     dma_write((nec.secl) ? nec.secl << 8 : nec.dtl);
  595.     nec.wcmd = (ddam) ? 0x09 : 0x05;
  596.  
  597.     LOG((log,"NEC765  command "));
  598.     if (out_nec(nec.mfm | nec.wcmd))        /* write sector */
  599.         return STA_2_NOT_READY;
  600.     if (out_nec((side << 2) + nec.unit))    /* side * 4 + unit */
  601.         return STA_2_NOT_READY;
  602.     if (out_nec(track))                     /* track */
  603.         return STA_2_NOT_READY;
  604.     if (out_nec(head))                        /* head (can be 0 for side 1!) */
  605.         return STA_2_NOT_READY;
  606.     if (out_nec(sector))                    /* sector */
  607.         return STA_2_NOT_READY;
  608.     if (out_nec(nec.secl))                    /* bytes per sector */
  609.         return STA_2_NOT_READY;
  610.     if (out_nec(nec.eot))                    /* end of track */
  611.         return STA_2_NOT_READY;
  612.     if (out_nec(nec.gap_a))                 /* gap_a */
  613.         return STA_2_NOT_READY;
  614.     if (out_nec(nec.dtl))                    /* data length */
  615.         return STA_2_NOT_READY;
  616.     LOG((log,"\n"));
  617.  
  618.     for (i = 0; i < 3; i++)
  619.     {
  620.         main_status();
  621.         if (!nec.stm.io_active)
  622.             break;
  623.         if (irq_flag)
  624.             break;
  625.     }
  626.  
  627.     results(0);
  628.  
  629.     return FDC_STA2(0);
  630. }
  631.  
  632. /*****************************************************************************
  633.  * real mode interrupt 0x0E
  634.  *****************************************************************************/
  635. static void irq_E(void)
  636. {
  637.     asm("nop                    \n" /* "nop" to find interrupt entry */
  638.         "sti                    \n" /* enable interrupts */
  639.         "pushl %eax             \n" /* save EAX */
  640.         "pushw %ds              \n" /* save DS */
  641.         "movw  $0x0000, %ax     \n" /* patched with _my_ds() */
  642.         "movw  %ax, %ds         \n" /* transfer to DS */
  643.         "orb   $0x80, _irq_flag \n" /* set IRQ occured flag */
  644.         "popw  %ds              \n" /* get back DS */
  645.         "movb  $0x20, %al       \n" /* end of interrupt */
  646.         "outb  %al, $0x20       \n" /* to PIC */
  647.         "popl  %eax             \n" /* get back EAX */
  648.         "iret                   \n");
  649. }
  650.  
  651. int osd_fdc_init(void)
  652. {
  653.     __dpmi_meminfo meminfo;
  654.     unsigned long _my_cs_base;
  655.     unsigned long _my_ds_base;
  656.     UINT8 *p;
  657.  
  658.     if (initialized)
  659.         return 1;
  660.  
  661.     log = fopen("nec.log", "w");
  662.  
  663.     for (p = (UINT8 *) & irq_E; p; p++)
  664.     {
  665.         /* found "nop" ? */
  666.         if (p[0] == 0x90)
  667.             new_irq_E.offset32 = (int) p + 1;
  668.         /* found "movw $0000,%ax" ? */
  669.         if ((p[0] == 0xb8) && (p[1] == 0x00) && (p[2] == 0x00))
  670.         {
  671.             p++;
  672.             *(short *)p = _my_ds();
  673.             break;
  674.         }
  675.     }
  676.  
  677.     __dpmi_get_segment_base_address(_my_cs(), &_my_cs_base);
  678.     __dpmi_get_segment_base_address(_my_ds(), &_my_ds_base);
  679.     __dpmi_get_protected_mode_interrupt_vector(0x0E, &old_irq_E);
  680.  
  681.     meminfo.handle = _my_cs();
  682.     meminfo.size = 128;           /* should be enough */
  683.     meminfo.address = _my_cs_base + (unsigned long) &irq_E;
  684.     if (__dpmi_lock_linear_region(&meminfo))
  685.     {
  686.         LOG((log,"NEC765 init: could not lock code %lx addr:%08lx size:%ld\n",
  687.                     meminfo.handle, meminfo.address, meminfo.size));
  688.         return 0;
  689.     }
  690.  
  691.     meminfo.handle = _my_ds();
  692.     meminfo.size = 128;           /* should be enough */
  693.     meminfo.address = _my_ds_base + (unsigned long) &old_irq_E;
  694.     if (__dpmi_lock_linear_region(&meminfo))
  695.     {
  696.         LOG((log,"NEC765 init: could not lock data\n"));
  697.         return 0;
  698.     }
  699.  
  700.     nec_dma.size = 4096;        /* request a 4K buffer for NEC DMA */
  701.     if (_go32_dpmi_allocate_dos_memory(&nec_dma))
  702.     {
  703.         LOG((log,"NEC765 init: could not alloc DOS memory size:%ld\n", nec_dma.size));
  704.         return 0;
  705.     }
  706.  
  707.     new_irq_E.selector = _my_cs();
  708.     if (__dpmi_set_protected_mode_interrupt_vector(0x0E, &new_irq_E))
  709.     {
  710.         LOG((log,"NEC765 init: could not set vector 0x0E"));
  711.         return 0;
  712.     }
  713.  
  714.     initialized = 1;
  715.  
  716.     atexit(osd_fdc_exit);
  717.  
  718.     specify();
  719.  
  720.     return 1;
  721. }
  722.  
  723. void osd_fdc_exit(void)
  724. {
  725.     __dpmi_meminfo meminfo;
  726.     unsigned long _my_cs_base;
  727.     unsigned long _my_ds_base;
  728.  
  729.     if (!initialized)
  730.         return;
  731.  
  732.     outportb(0x3f2, 0x0c);
  733.  
  734.     if (log)
  735.         fclose(log);
  736.  
  737.     __dpmi_get_segment_base_address(_my_cs(), &_my_cs_base);
  738.     __dpmi_get_segment_base_address(_my_ds(), &_my_ds_base);
  739.     __dpmi_set_protected_mode_interrupt_vector(0x0E, &old_irq_E);
  740.  
  741.     meminfo.handle = _my_cs();
  742.     meminfo.size = 128;           /* should be enough */
  743.     meminfo.address = _my_cs_base + (unsigned long) &irq_E;
  744.     __dpmi_unlock_linear_region(&meminfo);
  745.  
  746.     meminfo.handle = _my_ds();
  747.     meminfo.size = 128;           /* should be enough */
  748.     meminfo.address = _my_ds_base + (unsigned long) &old_irq_E;
  749.     __dpmi_unlock_linear_region(&meminfo);
  750.  
  751.     if (nec_dma.rm_segment)
  752.        _go32_dpmi_free_dos_memory(&nec_dma);
  753.  
  754.     if (log)
  755.         fclose(log);
  756.     log = NULL;
  757.  
  758.     initialized = 0;
  759. }
  760.  
  761. void osd_fdc_motors(UINT8 unit)
  762. {
  763.     nec.unit = unit;
  764.  
  765.     switch (nec.unit)
  766.     {
  767.         case 0: /* drive 0 */
  768.             if (!timer_motors)
  769.                 LOG((log, "FDD A: start\n"));
  770.             outportb(0x3f2, 0x1c);
  771.             break;
  772.         case 1: /* drive 1 */
  773.             if (!timer_motors)
  774.                 LOG((log, "FDD B: start\n"));
  775.             outportb(0x3f2, 0x2d);
  776.             break;
  777.     }
  778.     if (timer_motors)
  779.         timer_remove(timer_motors);
  780.     timer_motors = timer_set(10.0, nec.unit, osd_fdc_interrupt);
  781. }
  782.  
  783. /*****************************************************************************
  784.  * specify density, sectors per track and sector length
  785.  *****************************************************************************/
  786. void osd_fdc_density(UINT8 unit, UINT8 density, UINT8 tracks, UINT8 spt, UINT8 eot, UINT8 secl)
  787. {
  788. __dpmi_regs r = {{0,}, };
  789. int i;
  790.  
  791.     nec.unit = unit;
  792.     nec.eot = eot;
  793.     nec.secl = secl;
  794.     nec.dstep = 0;
  795.  
  796.     /* BIOS get current drive parameters */
  797.     r.x.ax = 0x0800;
  798.     r.h.dl = nec.unit;
  799.     __dpmi_int(0x13, &r);
  800.     nec.type = r.h.bl;
  801.  
  802.     if (nec.type != unit_type[nec.unit])
  803.     {
  804.         switch (nec.type)
  805.         {
  806.             case 1: /* 5.25" 360K */
  807.                 LOG((log,"NEC765 FDD %c: type 5.25\" 360K, sides %d, DOS spt %d%s\n",
  808.                         'A' + nec.unit, r.h.dh + 1, r.h.cl & 0x1f, (nec.dstep) ? " (double steps)":""));
  809.                 r.x.ax = 0x1701;
  810.                 break;
  811.             case 2: /* 5.25" 1.2M */
  812.                 if (tracks < 50)
  813.                     nec.dstep = 1;
  814.                 LOG((log,"NEC765 FDD %c: type 5.25\" 1.2M, sides %d, DOS spt %d%s\n",
  815.                         'A' + nec.unit, r.h.dh + 1, r.h.cl & 0x1f, (nec.dstep) ? " (double steps)":""));
  816.                 r.x.ax = 0x1703;
  817.                 break;
  818.             case 3: /* 3.5"  720K */
  819.                 if (tracks < 50)
  820.                     nec.dstep = 1;
  821.                 LOG((log,"NEC765 FDD %c: type 3.5\" 720K, sides %d, DOS spt %d%s\n",
  822.                         'A' + nec.unit, r.h.dh + 1, r.h.cl & 0x1f, (nec.dstep) ? " (double steps)":""));
  823.                 r.x.ax = 0x1704;
  824.                 break;
  825.             case 4: /* 3.5"  1.44M */
  826.                 if (tracks < 50)
  827.                     nec.dstep = 1;
  828.                 LOG((log,"NEC765 FDD %c: type 3.5\" 1.44M, sides %d, DOS spt %d%s\n",
  829.                         'A' + nec.unit, r.h.dh + 1, r.h.cl & 0x1f, (nec.dstep) ? " (double steps)":""));
  830.                 r.x.ax = 0x1703;
  831.                 break;
  832.             default: /* unknown */
  833.                 LOG((log,"NEC765 FDD %c: unknown type! sides %d, DOS spt %d\n",
  834.                         'A' + nec.unit, r.h.dh + 1, r.h.cl & 0x1f));
  835.                 r.x.ax = 0x1703;
  836.                 break;
  837.         }
  838.  
  839.         unit_type[nec.unit] = nec.type;
  840.         __dpmi_int(0x13, &r);
  841.  
  842.         for (i = 0; gaps[i].spt; i++)
  843.         {
  844.             if (gaps[i].density == density && gaps[i].secl == secl && spt <= gaps[i].spt)
  845.             {
  846.                 nec.gap_a = gaps[i].gap_a;
  847.                 nec.gap_b = gaps[i].gap_b;
  848.                 break;
  849.             }
  850.         }
  851.         if (gaps[i].spt)
  852.         {
  853.             LOG((log,"NEC765  using gaps entry #%d {%d,%d,%d,%d,%d} for %d,%d,%d\n",
  854.                 i,gaps[i].density,gaps[i].spt,gaps[i].secl,gaps[i].gap_a,gaps[i].gap_b,density,spt,secl));
  855.         }
  856.         else
  857.         {
  858.             LOG((log,"NEC765  ERR den:%d spt:%d secl:%d not found!\n",density,spt,secl));
  859.             nec.gap_a = 10;
  860.             nec.gap_b = 12;
  861.         }
  862.         nec.dtl = (secl)?0xff:0x80; /* data length */
  863.         nec.filler = 0xe5;            /* format filler UINT8 */
  864.  
  865.         LOG((log,"NEC765  FDD %c: den:%d trks:%d spt:%d eot:%d secl:%d gap_a:%d gap_b:%d\n",
  866.             'A' + nec.unit, density, tracks, spt, eot, secl, nec.gap_a, nec.gap_b));
  867.  
  868.         nec.rcmd = 0x26;    /* read command (0x26 normal, 0x2C deleted data address mark) */
  869.         nec.wcmd = 0x05;    /* write command (0x05 normal, 0x09 deleted data address mark) */
  870.     }
  871.  
  872.     switch (density)
  873.     {
  874.         case DEN_FM_LO:
  875.             nec.mfm = MFM_OVERRIDE; /* FM commands */
  876.             outportb(0x3f7, 0x02);    /* how do we set 125 kbps ?? */
  877.             break;
  878.         case DEN_FM_HI:
  879.             nec.mfm = MFM_OVERRIDE; /* FM commands */
  880.             outportb(0x3f7, 0x02);    /* set 250/300 kbps */
  881.             break;
  882.         case DEN_MFM_LO:
  883.             nec.mfm = 0x40;         /* MFM commands */
  884.             outportb(0x3f7, 0x02);    /* set 250/300 kbps */
  885.             break;
  886.         case DEN_MFM_HI:
  887.             nec.mfm = 0x40;         /* MFM commands */
  888.             outportb(0x3f7, 0x01);    /* set 500 kbps */
  889.             break;
  890.     }
  891. }
  892.  
  893. void osd_fdc_interrupt(int param)
  894. {
  895.     timer_motors = NULL;
  896.     /* stop the motor(s) */
  897.     LOG((log,"NEC765 FDD %c: stop", 'A' + param));
  898.     outportb(0x3f2, 0x0c);
  899. }
  900.  
  901. UINT8 osd_fdc_recal(UINT8 * track)
  902. {
  903.     LOG((log,"NEC765 recal\n"));
  904.  
  905.     irq_flag = 0;
  906.     LOG((log,"NEC765  command "));
  907.     if (out_nec(0x07))                  /* 1st recal command */
  908.         return STA_1_NOT_READY;
  909.     if (out_nec(nec.unit))
  910.         return STA_1_NOT_READY;
  911.     LOG((log,"\n"));
  912.  
  913.     seek_exec(track);
  914.     if (nec.sta.pcn)                    /* not yet on track 0 ? */
  915.     {
  916.         irq_flag = 0;
  917.         LOG((log,"NEC765  command "));
  918.         if (out_nec(0x07))                /* 2nd recal command */
  919.             return STA_1_NOT_READY;
  920.         if (out_nec(nec.unit))
  921.             return STA_1_NOT_READY;
  922.         LOG((log,"\n"));
  923.         seek_exec(track);
  924.     }
  925.  
  926.     /* reset unit type */
  927.     unit_type[nec.unit] = 0xff;
  928.  
  929.     return FDC_STA1();
  930. }
  931.  
  932. UINT8 osd_fdc_seek(UINT8 t, UINT8 * track)
  933. {
  934.     if (nec.sta.pcn == (t << nec.dstep))
  935.     {
  936.         *track = nec.sta.pcn;
  937.         return FDC_STA1();
  938.     }
  939.  
  940.     LOG((log,"NEC765 seek    unit:%d track:%02d\n", nec.unit, t));
  941.     irq_flag = 0;
  942.  
  943.     LOG((log,"NEC765  command "));
  944.     if (out_nec(0x0f))                  /* seek command */
  945.         return STA_1_NOT_READY;
  946.     if (out_nec(nec.unit))                /* unit number */
  947.         return STA_1_NOT_READY;
  948.     if (out_nec(t << nec.dstep))        /* track number */
  949.         return STA_1_NOT_READY;
  950.     LOG((log,"\n"));
  951.  
  952.     seek_exec(track);
  953.  
  954.     return FDC_STA1();
  955. }
  956.  
  957. UINT8 osd_fdc_step(int dir, UINT8 * track)
  958. {
  959. int new_track;
  960.     LOG((log,"NEC765 step    unit:%d direction:%+d (PCN:%02d)\n", nec.unit, dir, nec.sta.pcn));
  961.     irq_flag = 0;
  962.  
  963.     LOG((log,"NEC765  command "));
  964.     if (out_nec(0x0f))                  /* seek command */
  965.         return STA_1_NOT_READY;
  966.     if (out_nec(nec.unit))
  967.         return STA_1_NOT_READY;
  968.     new_track = nec.sta.pcn + (dir << nec.dstep);
  969.     if (new_track < 0)
  970.         new_track = 0;
  971.     if (new_track > 82)
  972.         new_track = 82;
  973.     if (out_nec(new_track))
  974.             return STA_1_NOT_READY;
  975.     LOG((log,"\n"));
  976.  
  977.     seek_exec(track);
  978.  
  979.     if (track)
  980.         *track = nec.sta.pcn;
  981.  
  982.     return FDC_STA1();
  983. }
  984.  
  985. UINT8 osd_fdc_format(UINT8 t, UINT8 h, UINT8 spt, UINT8 * fmt)
  986. {
  987. int i;
  988.  
  989.     /* let the motors run */
  990.     osd_fdc_motors(nec.unit);
  991.  
  992.     LOG((log,"NEC765 format  unit:%d track:%02d head:%d sec/track:%d\n", nec.unit, t, h, spt));
  993.  
  994. #if RE_INTERLEAVE
  995.     /* reorder the sector sequence for PC optimized reading (interleave) */
  996.     {
  997. UINT8 sec;
  998. UINT8 sec_min = 255;
  999. UINT8 sec_max = 0;
  1000.         for (i = 0; i < spt; i++)
  1001.         {
  1002.             sec = fmt[i * 4 + 2];
  1003.             if (sec < sec_min)
  1004.                 sec_min = sec;
  1005.             if (sec > sec_max)
  1006.                 sec_max = sec;
  1007.         }
  1008.         /* only reorder if all sectors from min to max are in the track! */
  1009.         if (sec_max - sec_min + 1 == spt)
  1010.         {
  1011.             LOG((log,"NEC765 reordered sectors:"));
  1012.             sec = sec_min;
  1013.             for (i = 0; i < spt; i++)
  1014.             {
  1015.                 LOG((log," %3d", sec));
  1016.                 fmt[i * 4 + 2] = sec;
  1017.                 sec += spt / RE_INTERLEAVE;
  1018.                 if (sec > sec_max)
  1019.                     sec = sec - spt + 1 - spt % RE_INTERLEAVE;
  1020.             }
  1021.             LOG((log,"\n"));
  1022.         }
  1023.     }
  1024. #endif
  1025.  
  1026.     nec.eot = 0;
  1027.     for (i = 0; i < spt; i++)
  1028.     {
  1029.         if (fmt[i * 4 + 2] > nec.eot)
  1030.             nec.eot = fmt[i * 4 + 2];
  1031.     }
  1032.  
  1033.     movedata(_my_ds(), (unsigned) fmt, nec_dma.pm_selector, nec_dma.pm_offset, spt * 4);
  1034.  
  1035.     irq_flag = 0;
  1036.  
  1037.     dma_write(spt * 4);
  1038.  
  1039.     LOG((log,"NEC765  command "));
  1040.     if (out_nec(nec.mfm | 0x0d))       /* format track */
  1041.         return STA_2_NOT_READY;
  1042.     if (out_nec((h << 2) + nec.unit))    /* head * 4 + unit select */
  1043.         return STA_2_NOT_READY;
  1044.     if (out_nec(nec.secl))                /* bytes per sector */
  1045.         return STA_2_NOT_READY;
  1046.     if (out_nec(spt))                    /* sectors / track */
  1047.         return STA_2_NOT_READY;
  1048.     if (out_nec(nec.gap_b))              /* gap_b */
  1049.         return STA_2_NOT_READY;
  1050.     if (out_nec(nec.filler))            /* format filler UINT8 */
  1051.         return STA_2_NOT_READY;
  1052.     LOG((log,"\n"));
  1053.  
  1054.     for (i = 0; i < 3; i++)
  1055.     {
  1056.         main_status();
  1057.         if (!nec.stm.io_active)
  1058.             break;
  1059.         if (irq_flag)
  1060.             break;
  1061.     }
  1062.  
  1063.     results(0);
  1064.  
  1065.     return FDC_STA2(0);
  1066. }
  1067.  
  1068. UINT8 osd_fdc_put_sector(UINT8 track, UINT8 side, UINT8 head, UINT8 sector, UINT8 *buff, UINT8 ddam)
  1069. {
  1070. UINT8 result;
  1071.  
  1072.     movedata(
  1073.         _my_ds(), (unsigned) buff,
  1074.         nec_dma.pm_selector, nec_dma.pm_offset,
  1075.         ((nec.secl) ? nec.secl << 8 : nec.dtl));
  1076.     result = write_sector(track, side, head, sector, ddam);
  1077.  
  1078.     return result;
  1079. }
  1080.  
  1081. UINT8 osd_fdc_get_sector(UINT8 track, UINT8 side, UINT8 head, UINT8 sector, UINT8 *buff)
  1082. {
  1083. UINT8 result;
  1084.  
  1085.     result = read_sector(track, side, head, sector);
  1086.     movedata(
  1087.         nec_dma.pm_selector, nec_dma.pm_offset,
  1088.         _my_ds(), (unsigned) buff,
  1089.         ((nec.secl) ? nec.secl << 8 : nec.dtl));
  1090.  
  1091.     return result;
  1092. }
  1093.